import com.thoughtworks.qdox.JavaProjectBuilder;
import com.thoughtworks.qdox.model.*;

import java.io.File;
import java.util.Collection;

public class RelationParser {
    /**
     * 获取Map、List等容器的泛化类型，如果泛化类型为直接泛型（E T K V N ?）则保留最深一层容器名
     *
     * @param field_str 成员变量类型（字符串）
     * @return 泛化类型
     */
    public static String getGenericType(String field_str) {
        while (field_str.startsWith("java.util") && field_str.contains("<")) {  //容器类都在java.util包中
            String tmp = field_str.substring(field_str.indexOf('<') + 1, field_str.lastIndexOf('>'));   //截取<>内的部分
            if (!isValid(tmp)) {
                break;
            } else {
                field_str = tmp;
            }
        }
        return field_str;
    }

    /**
     * 合法性判断，当变量是字符串、空类型、基本类型、基本类型包装类、直接泛型时非法，因为对分析两个类的关系没有贡献
     *
     * @param field_str 变量域字符串
     * @return 合法性判断结果
     */
    public static boolean isValid(String field_str) {
        return !field_str.equals("java.lang.String")
                && !field_str.equals("java.lang.String[]")
                && !field_str.startsWith("java.lang.Void")
                && !field_str.startsWith("void")
                && !field_str.startsWith("boolean")
                && !field_str.startsWith("byte")
                && !field_str.startsWith("char")
                && !field_str.startsWith("short")
                && !field_str.startsWith("int")
                && !field_str.startsWith("long")
                && !field_str.startsWith("float")
                && !field_str.startsWith("double")
                && !field_str.startsWith("java.util.concurrent.atomic.AtomicInteger")
                && !field_str.startsWith("java.util.concurrent.atomic.AtomicLong")
                && !field_str.startsWith("java.math.BigDecimal")
                && !field_str.startsWith("java.math.BigInteger")
                && !field_str.startsWith("java.lang.Byte")
                && !field_str.startsWith("java.lang.Double")
                && !field_str.startsWith("java.lang.Float")
                && !field_str.startsWith("java.lang.Integer")
                && !field_str.startsWith("java.lang.Long")
                && !field_str.startsWith("java.lang.Short")
                && !field_str.startsWith("java.lang.Boolean")
                && !field_str.startsWith("java.lang.Character")
                && !field_str.startsWith("java.lang.Enum")
                && !field_str.equals("E")
                && !field_str.equals("T")
                && !field_str.equals("K")
                && !field_str.equals("V")
                && !field_str.equals("N")
                && !field_str.equals("?");
    }

    /**
     * 使用Qdox解析源码类间关系：
     * 继承（Inheritance）
     * 实现（Realization）
     * 聚合（Aggregation）:A has a b。A保存了B的一个引用，A不直接实例化B，而是通过成员变量、构造方法或set 方法将外部的B 的实例 b注入到A中（对象注入）。
     * 组合（Composition）：与聚合相同点：一个类的实例是另外一个类的成员变量，通过在整体类的构造函数中实例化成员类来实现（两者同时实例化）
     * 依赖（Dependency）:一般而言，依赖关系在 Java 中体现为局域变量、方法参数，或者对静态方法的调用。
     * 关联（Association）:关联关系一般使用成员变量来实现。
     */
    public static void parser(String dir_path) {
        JavaProjectBuilder builder = new JavaProjectBuilder();
        builder.addSourceTree(new File(dir_path));  //需将源码解压为目录文件

        Collection<JavaClass> classes = builder.getClasses();

        int inheritance_count = 0;
        int realization_count = 0;
        int aggregation_count = 0;
        int composition_count = 0;
        int association_count = 0;
        int dependency_count = 0;

        for (JavaClass javaClass : classes) {
            //继承（Inheritance）
            JavaType super_class = javaClass.getSuperClass();
            if (super_class != null) { //接口或@interface父类为null
                if (!"class java.lang.Object".equals(super_class.toString())) { //不考虑顶级父类的父类（Object）
                    inheritance_count++;
                    System.out.println(javaClass.getFullyQualifiedName() + "\t" + super_class.getFullyQualifiedName() + "\t" + "Inheritance");
                }
            }

            //实现（Realization）
            for (JavaClass interface_class : javaClass.getInterfaces()) {
                if (interface_class != null) {
                    realization_count++;
                    System.out.println(javaClass.getFullyQualifiedName() + "\t" + interface_class.getFullyQualifiedName() + "\t" + "Realization");
                }
            }

            //聚合（Aggregation）
            boolean injection_flag = false; //对象注入标记
            for (JavaField field : javaClass.getFields()) { //获取类的成员变量
                String field_str = field.getType().toGenericString();
                if (isValid(field_str)) {   //过滤基本类型、字符串
                    if (!javaClass.getFullyQualifiedName().equals(field_str)) {  //过滤自聚合
                        for (JavaConstructor constructor : javaClass.getConstructors()) {   //通过构造器完成对象注入
                            for (JavaParameter javaParameter : constructor.getParameters()) {   //遍历构造器参数列表
                                if (javaParameter.toGenericString().equals(field_str)) { //含相同类型参数
                                    if (constructor.getSourceCode().contains(field.getName())) {    //构造器含成员变量名
                                        injection_flag = true;
                                    }
                                }
                            }
                        }
                        for (JavaMethod javaMethod : javaClass.getMethods()) {
                            if (javaMethod.getName().startsWith("set")) { //通过set方法完成对象注入
                                for (JavaParameter javaParameter : javaMethod.getParameters()) { //遍历set方法参数列表
                                    if (javaParameter.toGenericString().equals(field_str)) { //含相同类型参数
                                        if (javaMethod.getSourceCode().contains(field.getName())) { //set方法含成员变量名
                                            injection_flag = true;
                                        }
                                    }
                                }
                            }
                        }
                        for (JavaAnnotation javaAnnotation : field.getAnnotations()) {    //遍历成员变量的注解列表
                            if ("@Autowired".equals(javaAnnotation.toString())) { //Spring框架中可通过为属性添加@Autowired注解完成对象注入
                                injection_flag = true;
                            }
                        }
                        if (injection_flag) {
                            field_str = getGenericType(field_str);  //获取泛化类型
                            if (field_str.contains(",")) {  //拆分Map类型
                                String field_str1 = getGenericType(field_str.split(",")[0]);
                                String field_str2 = getGenericType(field_str.split(",")[1]);
                                if (isValid(field_str1)) {
                                    aggregation_count++;
                                    System.out.println(javaClass.getFullyQualifiedName() + "\t" + field_str1 + "\t" + "Aggregation");
                                }
                                if (isValid(field_str2)) {
                                    aggregation_count++;
                                    System.out.println(javaClass.getFullyQualifiedName() + "\t" + field_str2 + "\t" + "Aggregation");
                                }
                            } else {
                                aggregation_count++;
                                System.out.println(javaClass.getFullyQualifiedName() + "\t" + field_str + "\t" + "Aggregation");
                            }
                        }
                    }
                }
            }

            //组合（Composition）
            for (JavaField field : javaClass.getFields()) { //获取类的成员变量
                String field_str = field.getType().toGenericString();
                if (isValid(field_str)) {   //过滤基本类型、字符串
                    if (!javaClass.getFullyQualifiedName().equals(field_str)) {  //过滤自组合
                        for (JavaConstructor constructor : javaClass.getConstructors()) {   //通过构造器完成对象注入
                            boolean injection_flag1 = false; //对象注入标记
                            for (JavaParameter javaParameter : constructor.getParameters()) {   //遍历构造器参数列表
                                if (javaParameter.toGenericString().equals(field_str)) { //含相同类型参数
                                    injection_flag1 = true;
                                }
                            }
                            if (constructor.getSourceCode()
                                    .replace(" ", "")
                                    .replace("\n", "")
                                    .contains(field.getName() + "=new") && !injection_flag1) {
                                field_str = getGenericType(field_str);  //获取泛化类型
                                if (field_str.contains(",")) {  //拆分Map类型
                                    String field_str1 = getGenericType(field_str.split(",")[0]);
                                    String field_str2 = getGenericType(field_str.split(",")[1]);
                                    if (isValid(field_str1)) {
                                        composition_count++;
                                        System.out.println(javaClass.getFullyQualifiedName() + "\t" + field_str1 + "\t" + "Aggregation");
                                    }
                                    if (isValid(field_str2)) {
                                        composition_count++;
                                        System.out.println(javaClass.getFullyQualifiedName() + "\t" + field_str2 + "\t" + "Aggregation");
                                    }
                                } else {
                                    composition_count++;
                                    System.out.println(javaClass.getFullyQualifiedName() + "\t" + field_str + "\t" + "Composition");
                                }
                            }
                        }
                    }
                }
            }

            //关联（Association）
            for (JavaField field : javaClass.getFields()) { //获取类的成员变量
                String field_str = field.getType().toGenericString();
                if (isValid(field_str)) {   //过滤基本类型、字符串
                    if (!javaClass.getFullyQualifiedName().equals(field_str)) {  //过滤自组合
                        field_str = getGenericType(field_str);  //获取泛化类型
                        if (field_str.contains(",")) {  //拆分Map类型
                            String field_str1 = getGenericType(field_str.split(",")[0]);
                            String field_str2 = getGenericType(field_str.split(",")[1]);
                            if (isValid(field_str1)) {
                                association_count++;
                                System.out.println(javaClass.getFullyQualifiedName() + "\t" + field_str1 + "\t" + "Association");
                            }
                            if (isValid(field_str2)) {
                                association_count++;
                                System.out.println(javaClass.getFullyQualifiedName() + "\t" + field_str2 + "\t" + "Association");
                            }
                        } else {
                            association_count++;
                            System.out.println(javaClass.getFullyQualifiedName() + "\t" + field_str + "\t" + "Association");
                        }
                    }
                }
            }

            //依赖（Dependency）
            for (JavaMethod javaMethod : javaClass.getMethods()) {
                for (JavaParameter javaParameter : javaMethod.getParameters()) {  //通过方法参数访问B
                    String parameter_str = getGenericType(javaParameter.getType().toGenericString());
                    if (isValid(parameter_str)) {
                        if (parameter_str.contains(",")) {
                            String parameter_str1 = getGenericType(parameter_str.split(",")[0]);
                            String parameter_str2 = getGenericType(parameter_str.split(",")[1]);
                            if (isValid(parameter_str1)) {
                                for (JavaClass jc : classes) {
                                    String jc_name = jc.getFullyQualifiedName();
                                    if (parameter_str1.equals(jc_name) && !jc_name.equals((javaClass.getFullyQualifiedName()))) {
                                        dependency_count++;
                                        System.out.println(javaClass.getFullyQualifiedName() + "\t" + jc_name + "\t" + "Dependency");
                                    }
                                }
                            }
                            if (isValid(parameter_str2)) {
                                for (JavaClass jc : classes) {
                                    String jc_name = jc.getFullyQualifiedName();
                                    if (parameter_str2.equals(jc_name) && !jc_name.equals((javaClass.getFullyQualifiedName()))) {
                                        dependency_count++;
                                        System.out.println(javaClass.getFullyQualifiedName() + "\t" + jc_name + "\t" + "Dependency");
                                    }
                                }
                            }
                        } else {
                            for (JavaClass jc : classes) {
                                String jc_name = jc.getFullyQualifiedName();
                                if (parameter_str.equals(jc_name) && !jc_name.equals((javaClass.getFullyQualifiedName()))) {
                                    dependency_count++;
                                    System.out.println(javaClass.getFullyQualifiedName() + "\t" + jc_name + "\t" + "Dependency");
                                }
                            }
                        }
                    }
                }
                for (JavaClass jc : classes) {  //通过方法返回值、方法局部变量、静态方法的调用(B.static_method())来访问B
                    String jc_name = jc.getFullyQualifiedName();
                    if (javaMethod.getSourceCode().contains(jc_name) && !jc_name.equals((javaClass.getFullyQualifiedName()))) {
                        dependency_count++;
                        System.out.println(javaClass.getFullyQualifiedName() + "\t" + jc_name + "\t" + "Dependency");
                    }
                }
            }
        }
        System.out.println("解析到 " + inheritance_count + " 个继承（Inheritance）关系");
        System.out.println("解析到 " + dependency_count + " 个依赖（Dependency）关系");
        System.out.println("解析到 " + aggregation_count + " 个聚合（Aggregation）关系");
        System.out.println("解析到 " + composition_count + " 个组合（Composition）关系");
        System.out.println("解析到 " + association_count + " 个关联（Association）关系");
        System.out.println("解析到 " + realization_count + " 个实现（Realization）关系");
    }
}
